package com.leyou.item.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.mapper.StockMapper;
import com.leyou.item.pojo.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class GoodsService {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private SpuDetailMapper spuDetailMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private StockMapper stockMapper;

    @Autowired
    private AmqpTemplate amqpTemplate;

    public PageResult<SpuBo> querySpuByPageAndSort(Integer page, Integer rows, Boolean saleable, String key) {
        //开始分业
        PageHelper.startPage(page, rows);

        //SpuBo是封装数据传给前端，真正与数据库交互的还是Spu实体类
        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();

        //是否过滤上下架
        if (saleable != null) {
            criteria.andEqualTo("saleable", saleable);
        }
        //模糊查询
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("title", "%" + key + "%");
        }
        //进行查询，返回Page对象
        Page<Spu> pageInfo = (Page<Spu>) this.spuMapper.selectByExample(example);

        //接下来的操作是把Spu里的cids和bid替换为实际数据
        //用的技术是Jdk8 新增的Stream流
        //getResult()方法是获得分页结果的list集合
        List<SpuBo> list = pageInfo.getResult().stream().map(spu -> {
            //属性拷贝
            SpuBo spuBo = new SpuBo();
            //将spu的属性拷贝到spuBo
            BeanUtils.copyProperties(spu, spuBo);

            //查询商品的三级分类信息
            List<String> names = this.categoryService.queryNamesByCids(
                    Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
            //将集合中的三级分类信息用“/”进行拼接
            spuBo.setCname(StringUtils.join(names, "/"));

            //查询商品的品牌信息
            Brand brand = this.brandService.queryBrandByBid(spu.getBrandId());
            spuBo.setBname(brand.getName());
            return spuBo;
        }).collect(Collectors.toList());//对流处理结果 进行处理收集
        //返回分页信息
        return new PageResult<>(pageInfo.getTotal(), list);
    }

    //新增商品,逻辑较为复杂，除了要对SPU新增以外，还要对SpuDetail、Sku、Stock进行保存
    @Transactional
    public void saveGoods(SpuBo spuBo) {
        //先保存spu
        Spu spu = new Spu();
        BeanUtils.copyProperties(spuBo, spu);
        //给spu中的一些属性赋值
        spu.setSaleable(true);
        spu.setValid(true);
        spu.setCreateTime(new Date());
        spu.setLastUpdateTime(spuBo.getCreateTime());
        this.spuMapper.insert(spu);

        //保存spuDetail,除了spuid 其余数据都封装在spubo中
        SpuDetail spuDetail = spuBo.getSpuDetail();
        spuDetail.setSpuId(spu.getId());//spu插入数据库后有主键回显
        this.spuDetailMapper.insert(spuDetail);

        //保存sku 和 库存信息
        List<Sku> skus = spuBo.getSkus();
        //使用jdk8的lambda表达式进行处理
        skus.forEach(sku -> {
            //保存sku
            //先给其中一些没有从前端传过来的属性赋值
            sku.setSpuId(spu.getId());
            sku.setEnable(true);
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            this.skuMapper.insert(sku);

            //保存库存信息
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());//在填表的时候，填写sku属性的时候输入了库存数量
            this.stockMapper.insert(stock);
        });

        //新增执行成功之后,发送消息 只有添加成功后才会生成id，所以使用spu对象来获取id 否则用spubo直接获取不到
        this.sendMessage(spu.getId(),"insert");
    }

    //修改商品之回显spu
    public SpuDetail querySpuDetailById(Long id) {
        SpuDetail spuDetail = this.spuDetailMapper.selectByPrimaryKey(id);
        return spuDetail;
    }

    //修改商品之回显sku和stock（库存）
    public List<Sku> querySkuById(Long id) {
        Sku sku = new Sku();
        sku.setSpuId(id);
        List<Sku> skus = this.skuMapper.select(sku);
        //查询库存信息
        skus.forEach(sku1 -> {
            Stock stock = this.stockMapper.selectByPrimaryKey(sku1.getId());
            sku1.setStock(stock.getStock());
        });
        return skus;
    }

    //提交修改商品信息请求
    //spu数据可以修改，但是SKU数据无法修改，因为有可能之前存在的SKU现在已经不存在了，或者以前的sku属性都不存在了
    //因此这里直接删除以前的SKU，然后新增即可
    @Transactional
    public void updateGoods(SpuBo spuBo) {
        //先更新spu
        Spu spu = new Spu();
        BeanUtils.copyProperties(spuBo, spu);
        //给spu中的一些属性赋值
        spu.setSaleable(true);
        spu.setValid(true);
        spu.setCreateTime(new Date());
        spu.setLastUpdateTime(spuBo.getCreateTime());
        this.spuMapper.updateByPrimaryKeySelective(spu);

        //更新spuDetail,除了spuid 其余数据都封装在spubo中
        this.spuDetailMapper.updateByPrimaryKeySelective(spuBo.getSpuDetail());


        // 查询以前sku
        List<Sku> skus = this.querySkuById(spuBo.getId());
        // 如果以前存在，则删除
        if (!CollectionUtils.isEmpty(skus)) {
            List<Long> ids = skus.stream().map(sku -> sku.getId()).collect(Collectors.toList());
            // 删除以前库存
            Example example = new Example(Stock.class);
            example.createCriteria().andIn("skuId", ids);
            this.stockMapper.deleteByExample(example);

            // 删除以前的sku
            Sku record = new Sku();
            record.setSpuId(spuBo.getId());
            this.skuMapper.delete(record);

        }
        // 新增sku和库存
        //保存sku 和 库存信息
        List<Sku> skusnew = spuBo.getSkus();
        //使用jdk8的lambda表达式进行处理
        skusnew.forEach(sku -> {
            //保存sku
            //先给其中一些没有从前端传过来的属性赋值
            sku.setSpuId(spu.getId());
            sku.setEnable(true);
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            this.skuMapper.insert(sku);

            //保存库存信息
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());//在填表的时候，填写sku属性的时候输入了库存数量
            this.stockMapper.insert(stock);
        });

        //修改完成之后，发送消息
        this.sendMessage(spuBo.getId(),"update");

    }

    //修改spu的为下架
    public int soldout(Long spuid) {
        Spu spu = new Spu();
        spu.setId(spuid);
        spu.setSaleable(false);
        int i = this.spuMapper.updateByPrimaryKeySelective(spu);
        return i;
    }

    //修改spu的为上架
    public int onsale(Long spuid) {
        Spu spu = new Spu();
        spu.setId(spuid);
        spu.setSaleable(true);
        int i = this.spuMapper.updateByPrimaryKeySelective(spu);
        return i;
    }


    //删除商品，同时要删除商品详情，sku表和stock表中的数据
    @Transactional
    public int delGoods(Long spuid) {
        try {
            //先删除sku和库存
            // 查询与被删商品相关的sku
            List<Sku> skus = this.querySkuById(spuid);
            // 如果存在，则删除
            if (!CollectionUtils.isEmpty(skus)) {
                List<Long> ids = skus.stream().map(sku -> sku.getId()).collect(Collectors.toList());
                // 删除库存
                Example example = new Example(Stock.class);
                example.createCriteria().andIn("skuId", ids);
                this.stockMapper.deleteByExample(example);

                // 删除sku
                Sku record = new Sku();
                record.setSpuId(spuid);
                this.skuMapper.delete(record);
            }

            //再删除spu和spudetail
            this.spuDetailMapper.deleteByPrimaryKey(spuid);
            this.spuMapper.deleteByPrimaryKey(spuid);

            //删除操作完成之后，发送消息
            this.sendMessage(spuid,"delete");

            return 1;//上述均执行成功，则返回一个大于0的数值
        } catch (Exception e) {
            e.printStackTrace();
        }
        //删除失败之后的返回值，代表对数据库操作了0条
        return 0;
    }

    //根据spu的id查询spu信息
    public Spu querySpuById(Long id) {
        Spu spu = this.spuMapper.selectByPrimaryKey(id);
        return spu;
    }

    //封装一个发送消息到mq的方法
    public void sendMessage(Long id, String type) {
        // 发送消息
        try {
            this.amqpTemplate.convertAndSend("item." + type, id);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //根据skutitle查询sku的信息
    public List<Sku> querySkuBySkuId(List<String> skutitles) {
        List<Sku> list = new ArrayList<>();
        for (String skutitle : skutitles) {
            Sku sku = new Sku();
            sku.setTitle(skutitle);
            Sku sku1 = this.skuMapper.selectOne(sku);
            list.add(sku1);
        }
        return list;
    }

    //根据前台传过来的skutitle来获取sku信息，再通过sku中包含的spuid来查询相对应的spu
    //根据spu中的saleable的值，来判断该商品是否处于下架状态
    public List<Map<String,Object>> querySpuBySku(List<String> skutitles) {
        List<Map<String,Object>> list = new ArrayList<>();
        for (String skutitle : skutitles) {
            Sku sku = new Sku();
            sku.setTitle(skutitle);
            Sku sku1 = this.skuMapper.selectOne(sku);
            //根据sku信息得到对应的spuId
            Long spuId = sku1.getSpuId();
            //调用本类中的方法
            Spu spu = this.querySpuById(spuId);
            //创建一个map，来存放 对应每个sku对应的上下架信息,key是skutitle，value是上下架信息
            Map<String,Object> map = new HashMap<>();
            map.put(skutitle,spu.getSaleable());
            list.add(map);
        }
        return list;
    }
}
